package com.zjlab.georeceive;

import com.zjlab.SmConfig;
import com.zjlab.georeceive.handler.GeoReceiveUdpHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author xue
 * @create 2022-11-07 16:09
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class GeoReceiveUdp {

    private EventLoopGroup group;

    private final GeoReceiveUdpHandler geoReceiveUdpHandler;
    private final SmConfig smConfig;

    @PostConstruct
    public void init() throws InterruptedException {
        group = new NioEventLoopGroup(2, new ThreadFactory() {
            private final AtomicInteger count = new AtomicInteger(0);

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "Geo接收" + count.getAndIncrement());
            }
        });
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                // 主线程处理
                .channel(NioDatagramChannel.class)
                // 广播
                .option(ChannelOption.SO_BROADCAST, true)
                // 设置udp单帧超过2M的办法
                //.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(65535))
                // 设置读缓冲区为2M
                .option(ChannelOption.SO_RCVBUF, 2048 * 1024)
                // 设置写缓冲区为1M
                .option(ChannelOption.SO_SNDBUF, 1024 * 1024)
                .handler(new ChannelInitializer<NioDatagramChannel>() {

                    @Override
                    protected void initChannel(NioDatagramChannel ch) {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(geoReceiveUdpHandler);
                    }
                });

        ChannelFuture f = bootstrap.bind(smConfig.getGeoPort()).sync();
        log.info("Geo接收端{}正在监听中……", smConfig.getGeoPort());
        // 异步监听关闭信息
        f.channel().closeFuture().addListener((ChannelFutureListener) channelFuture -> {
            log.info("Geo接收端{}监听被关闭……", smConfig.getGeoPort());
        });
    }


    @PreDestroy
    public void stop() {
        log.info("销毁Geo接收端");
        if (ObjectUtils.isEmpty(group)) {
            group.shutdownGracefully();
        }
    }

}
